/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable @typescript-eslint/no-explicit-any */
import {
  useUIStore,
  useNamespace,
  IBizCustomRender,
  useControlController,
  hasEmptyPanelRenderer,
} from '@ibiz-template/vue3-util';
import {
  h,
  ref,
  watch,
  VNode,
  computed,
  PropType,
  onUnmounted,
  defineComponent,
  resolveComponent,
  VNodeArrayChildren,
} from 'vue';
import { IDEGrid, IDEGridColumn } from '@ibiz/model-core';
import { IControlProvider, ScriptFactory } from '@ibiz-template/runtime';
import { Namespace, NOOP } from '@ibiz-template/core';
import { createUUID } from 'qx-util';
import {
  IGridProps,
  usePagination,
  useAppGridBase,
  useITableEvent,
  useGridHeaderStyle,
} from './use';
import { GridController } from '../../controller';
import { IColumnExState } from '../../interface';
import './grid.scss';

export const GridControl = defineComponent({
  name: 'IBizGridControl',
  props: {
    modelData: { type: Object as PropType<IDEGrid>, required: true },
    context: { type: Object as PropType<IContext>, required: true },
    params: { type: Object as PropType<IParams>, default: () => ({}) },
    provider: { type: Object as PropType<IControlProvider> },
    mdctrlActiveMode: { type: Number, default: undefined },
    singleSelect: { type: Boolean, default: undefined },
    rowEditOpen: { type: Boolean, default: undefined },
    isSimple: { type: Boolean, required: false },
    data: { type: Array<IData>, required: false },
    loadDefault: { type: Boolean, default: true },
  },
  setup(props) {
    const c: GridController = useControlController(
      (...args) => new GridController(...args),
    );
    const ns = useNamespace(
      `control-${c.model.controlType!.toLowerCase()}`,
    ) as unknown as Namespace;

    // 无限滚动元素
    const infiniteScroll = ref<IData>();
    // 无限滚动元素标识
    const infiniteScrollKey = ref<string>(createUUID());

    const { zIndex } = useUIStore();
    c.state.zIndex = zIndex.increment();

    const {
      UUID,
      tableRef,
      onRowClick,
      onDbRowClick,
      onSortChange,
      onSelectionChange,
      cleanKeyUp = NOOP,
      handleRowClassName,
      cleanKeyDown = NOOP,
      handleHeaderCellClassName,
    } = useITableEvent(c);
    const { onPageChange, onPageRefresh, onPageSizeChange } = usePagination(c);

    const { headerCssVars } = useGridHeaderStyle(tableRef, ns);

    const { tableData, defaultSort, spanMethod, summaryMethod, headerDragend } =
      useAppGridBase(c, props as IGridProps);

    // 是否可以加载更多
    const isLodeMoreDisabled = computed(() => {
      if (c.model.pagingMode !== 2) {
        return true;
      }
      return (
        c.state.items.length >= c.state.total ||
        c.state.isLoading ||
        c.state.total <= c.state.size
      );
    });

    const popperClass = computed(() => {
      return c.model.sysCss?.cssName ? `${c.model.sysCss.cssName}--popper` : '';
    });

    watch(
      () => c.state.curPage,
      () => {
        if (
          c.state.curPage === 1 &&
          (c.model.pagingMode === 2 || c.model.pagingMode === 3)
        ) {
          infiniteScrollKey.value = createUUID();
          const containerEl =
            infiniteScroll.value?.ElInfiniteScroll?.containerEl;
          if (containerEl) {
            containerEl.lastScrollTop = 0;
            containerEl.scrollTop = 0;
          }
        }
      },
    );

    const renderAttrs = (
      model: IDEGridColumn | IDEGrid,
      params: IParams,
      ignore: string[] = [],
    ): IParams => {
      const attrs: IParams = {};
      model.controlAttributes?.forEach(item => {
        if (
          item.attrName &&
          item.attrValue &&
          !ignore.includes(item.attrName)
        ) {
          attrs[item.attrName!] = ScriptFactory.execSingleLine(
            item.attrValue!,
            {
              ...params,
            },
          );
        }
      });
      return attrs;
    };

    /**
     * 绘制无数据提示
     *
     * @return {*}  {(VNode | null)}
     */
    const renderNoData = (): VNode | null => {
      // 未加载不显示无数据
      const { isLoaded } = c.state;
      if (isLoaded) {
        const quickToolbar = c.model.controls?.find(
          item => item.name === `${c.model.name}_quicktoolbar`,
        );
        if (quickToolbar) {
          return (
            <iBizToolbarControl
              modelData={quickToolbar}
              context={c.context}
              params={c.params}
              class={ns.b('quick-toolbar')}
            ></iBizToolbarControl>
          );
        }
        const noDataSlots: IParams = {};
        if (hasEmptyPanelRenderer(c)) {
          Object.assign(noDataSlots, {
            customRender: () => (
              <IBizCustomRender controller={c}></IBizCustomRender>
            ),
          });
        }
        return (
          <iBizNoData
            text={c.model.emptyText}
            emptyTextLanguageRes={c.model.emptyTextLanguageRes}
            hideNoDataImage={c.state.hideNoDataImage}
          >
            {noDataSlots}
          </iBizNoData>
        );
      }
      // 给null 表格会绘制默认的无数据
      return <div></div>;
    };

    /**
     * 绘制批操作工具栏
     *
     * @return {*}  {(VNode | undefined)}
     */
    const renderBatchToolBar = (): VNode | undefined => {
      const batchToolbar = c.model.controls?.find(item => {
        return item.name === `${c.model.name!}_batchtoolbar`;
      });
      if (!batchToolbar || c.state.singleSelect) {
        return;
      }
      return (
        <div
          class={[
            ns.b('batch-toolbar'),
            ns.is('show', c.state.selectedData.length > 0),
          ]}
        >
          <div class={ns.b('batch-toolbar-content')}>
            <div class={ns.b('batch-toolbar-text')}>
              {ibiz.i18n.t('control.common.itemsSelected', {
                length: c.state.selectedData.length,
              })}
            </div>
            <div class={ns.b('batch-toolbar-separator')}>|</div>
            <iBizToolbarControl
              modelData={batchToolbar}
              context={c.context}
              params={c.params}
              class={ns.b('batch-toolbar-items')}
            ></iBizToolbarControl>
          </div>
        </div>
      );
    };

    const renderColumn = (
      state: IColumnExState,
      isAdaptive: boolean,
    ): VNode | undefined => {
      const columnC = c.columns[state.key];
      if (state.hidden || !columnC) return;
      const model = columnC.model;
      const widthFlexGrow =
        columnC.isAdaptiveColumn || (!c.hasAdaptiveColumn && isAdaptive);
      const widthName = widthFlexGrow ? 'min-width' : 'width';
      return (
        <el-table-column
          label={model.caption}
          prop={state.key}
          fixed={state.fixed}
          {...{ [widthName]: state.columnWidth }}
          sortable={
            model.enableSort ? c.model.sortMode === 'LOCAL' || 'custom' : false
          }
          sortMethod={(a: IData, b: IData) => {
            const fieldName = model.id!.toLowerCase();
            if (a[fieldName] < b[fieldName] || !a[fieldName]) return -1;
            if (a[fieldName] > b[fieldName] || !b[fieldName]) return 1;
            return 0;
          }}
          align={model.align?.toLowerCase() || 'center'}
          className={`${model.columnType!.toLowerCase()}-${state.key}`}
          {...renderAttrs(model, c.getEventArgs())}
        >
          {{
            header: ({ column }: IData) => {
              return (
                <iBizGridColumnHeader
                  key={column.property}
                  controller={columnC}
                />
              );
            },
            default: ({ row }: IData) => {
              if (model.columnType === 'GROUPGRIDCOLUMN') {
                return state.children?.map(child => {
                  return renderColumn(child, widthFlexGrow);
                });
              }
              let elRow = row;
              if (row.isGroupData) elRow = row.first;
              const rowState = c.findRowState(elRow);
              if (rowState) {
                const comp = resolveComponent(c.providers[state.key].component);
                return h(comp, {
                  controller: columnC,
                  row: rowState,
                  key: elRow.tempsrfkey + state.key,
                  attrs: renderAttrs(model, {
                    ...c.getEventArgs(),
                    data: rowState.data,
                  }),
                });
              }
              return;
            },
          }}
        </el-table-column>
      );
    };

    const renderTableColumn = () => {
      const showColumns = c.state.columnStates.filter(state => !state.hidden);
      return c.state.columnStates.map(state => {
        const index = showColumns.findIndex(column => column.key === state.key);
        return renderColumn(state, index === showColumns.length - 1);
      });
    };

    onUnmounted(() => {
      zIndex.decrement();
      if (cleanKeyDown !== NOOP) {
        cleanKeyDown();
      }
      if (cleanKeyUp !== NOOP) {
        cleanKeyUp();
      }
    });

    return {
      c,
      ns,
      UUID,
      tableRef,
      tableData,
      defaultSort,
      popperClass,
      headerCssVars,
      infiniteScroll,
      infiniteScrollKey,
      isLodeMoreDisabled,
      spanMethod,
      onRowClick,
      renderAttrs,
      onSortChange,
      onPageChange,
      onDbRowClick,
      renderNoData,
      onPageRefresh,
      summaryMethod,
      headerDragend,
      onPageSizeChange,
      onSelectionChange,
      renderBatchToolBar,
      handleRowClassName,
      renderTableColumn,
      handleHeaderCellClassName,
    };
  },
  render() {
    if (!this.c.state.isCreated) {
      return;
    }
    return (
      <iBizControlNavigation controller={this.c}>
        <iBizControlBase
          class={[
            this.ns.b(),
            this.ns.is('show-header', !this.c.state.hideHeader),
            this.ns.is('enable-page', this.c.state.enablePagingBar),
            this.ns.is('enable-group', this.c.model.enableGroup),
            this.ns.is('enable-drop', this.c.model.enableRowEditOrder),
            this.ns.is('single-select', this.c.state.singleSelect),
            this.ns.is('empty', this.c.state.items.length === 0),
          ]}
          controller={this.c}
          style={this.headerCssVars}
        >
          {
            <el-table
              border
              ref='tableRef'
              key={this.UUID}
              row-key='tempsrfkey'
              data={this.tableData}
              tooltip-effect='light'
              class={this.ns.e('table')}
              scrollbar-always-on={true}
              default-sort={this.defaultSort}
              show-summary={this.c.enableAgg}
              show-header={!this.c.state.hideHeader}
              highlight-current-row={this.c.state.singleSelect}
              onRowClick={this.onRowClick}
              span-method={this.spanMethod}
              onSortChange={this.onSortChange}
              onRowDblclick={this.onDbRowClick}
              summary-method={this.summaryMethod}
              onHeaderDragend={this.headerDragend}
              row-class-name={this.handleRowClassName}
              onSelectionChange={this.onSelectionChange}
              expandRowKeys={this.c.state.expandRowKeys}
              header-cell-class-name={this.handleHeaderCellClassName}
              {...this.$attrs}
              {...this.renderAttrs(this.c.model, this.c.getEventArgs(), [
                'rowClassName',
                'headerCellClassName',
              ])}
            >
              {{
                empty: this.renderNoData,
                default: (): VNodeArrayChildren => {
                  return [
                    !this.c.state.singleSelect && (
                      <el-table-column
                        width='55'
                        align='center'
                        type='selection'
                        reserve-selection={true}
                        class-name={this.ns.e('selection')}
                      ></el-table-column>
                    ),
                    this.renderTableColumn(),
                  ];
                },
                append: () => {
                  return [
                    <div
                      ref={'infiniteScroll'}
                      key={this.infiniteScrollKey}
                      v-infinite-scroll={() => this.c.loadMore()}
                      infinite-scroll-distance={10}
                      infinite-scroll-disabled={this.isLodeMoreDisabled}
                    ></div>,
                    this.c.model.pagingMode === 3 &&
                      !(
                        this.c.state.items.length >= this.c.state.total ||
                        this.c.state.isLoading ||
                        this.c.state.total <= this.c.state.size
                      ) && (
                        <div class={this.ns.e('load-more-button')}>
                          <el-button text onClick={() => this.c.loadMore()}>
                            {ibiz.i18n.t('control.common.loadMore')}
                          </el-button>
                        </div>
                      ),
                  ];
                },
              }}
            </el-table>
          }
          {this.c.state.enablePagingBar && (
            <iBizGridPagination
              size={this.c.state.size}
              total={this.c.state.total}
              curPage={this.c.state.curPage}
              popperClass={this.popperClass}
              pageSizes={this.c.state.pageSizes}
              totalPages={this.c.state.totalPages}
              onChange={this.onPageChange}
              onPageSizeChange={this.onPageSizeChange}
            ></iBizGridPagination>
          )}
          {this.renderBatchToolBar()}
        </iBizControlBase>
      </iBizControlNavigation>
    );
  },
});
